﻿#region Using directives

using System;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;

using System.CodeDom;

using Weazel.Gezel.Conversions.CodeGeneration;

#endregion

namespace Weazel.Gezel.Conversions.Model
{
	public abstract class Type : CodeTypeDeclaration
	{
		private Dictionary<string, Field> fields;
		public Dictionary<string, Field> Fields
		{
			get { return fields; }
		}

		protected Dictionary<string, string> comments;
		public Dictionary<string, string> Comments
		{
			get { return comments; }
		}

		public string InstanceName
		{
			get
			{
				// parent name should be in pascal case
				Debug.Assert(Char.IsUpper(Name[0]));
				return Char.ToLower(Name[0]) + Name.Substring(1);
			}
		}

		protected SoftwareModel softwareModel;
		public SoftwareModel SoftwareModel
		{
			get
			{
				return softwareModel;
			}
		}

		protected Type(string name, SoftwareModel softwareModel)
			: base(name)
		{
			this.softwareModel = softwareModel;
			this.fields = new Dictionary<string, Field>();
			this.comments = new Dictionary<string, string>();
		}

		public IntegerField AddIntegerField(string name, int width, bool signed, string initialValue)
		{
			if (!fields.ContainsKey(name))
			{
				IntegerField field = new IntegerField(name, width, signed, initialValue);
				field.Attributes = MemberAttributes.Assembly;
				fields[name] = field;
				this.Members.Add(field);
				return field;
			}			
			else
			{
				return (IntegerField)fields[name];
			}
		}

		public Field AddField(string name, string typename)
		{
			if (!fields.ContainsKey(name))
			{
				Field field = new Field(name, typename);
				field.Attributes = MemberAttributes.Assembly;
				fields[name] = field;
				this.Members.Add(field);
				return field;
			}
			else if (fields.ContainsKey(name) && fields[name].Type.BaseType != typename)
			{
				throw new ApplicationException("field already exists with other type");
			}
			else
			{
				return fields[name];
			}
		}


		public Field AddStaticField(string name, string typename)
		{
			if (!fields.ContainsKey(name))
			{
				Field field = new Field(name, typename);
				field.Attributes = MemberAttributes.Static | MemberAttributes.Assembly;
				fields[name] = field;
				this.Members.Add(field);
				return field;
			}
			else if (fields.ContainsKey(name) && fields[name].Type.BaseType != typename)
			{
				throw new ApplicationException("field already exists with other type");
			}
			else
			{
				return fields[name];
			}
		}		

		public Method AddMethod(string name)
		{
			Method newMethod = new Method(name);
			newMethod.Attributes = MemberAttributes.Public & MemberAttributes.AccessMask;
			Members.Add(newMethod);
			return newMethod;
		}

		public Method AddStaticMethod(string name, string returnType)
		{
			Method newMethod = new Method(name, returnType, true, this);
			newMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
			Members.Add(newMethod);
			return newMethod;
		}
	}
}
